cc.Class({
    extends: require("BasePanel"),

    properties: {
        manifestUrl: {
            type: cc.Asset,
            default: null
        },
        progressBar: cc.ProgressBar,
        infoLabel: cc.Label,
        _updating: false,
    },

    onEnter(args) {
        this._super(args, false);

        this.canRetryTime = 3;

        this._initAssetsManager();
        this._checkUpdate();
    },
    onTouchStart() { },

    _checkCb: function (event) {
        console.log('Code1: ' + event.getEventCode());
        let needUpdate = false;

        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                console.log('ERROR_NO_LOCAL_MANIFEST =====');
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
                console.log('ERROR_DOWNLOAD_MANIFEST =====');
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                console.log('ERROR_PARSE_MANIFEST =====');
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                console.log('ALREADY_UP_TO_DATE =====');
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND:
                console.log('NEW_VERSION_FOUND =====');
                this.progressBar.progress = 0;
                needUpdate = true;
                break;
            default:
                return;
        }

        this._am.setEventCallback(null);
        this._checkListener = null;
        this._updating = false;

        if (!needUpdate) {
            this.enterArgs.delegate && this.enterArgs.delegate();
            return;
        }


        this._hotUpdate();
    },

    _updateCb: function (event) {
        console.log('Code: ' + event.getEventCode());
        var needRestart = false;
        var failed = false;
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                console.log('ERROR_NO_LOCAL_MANIFEST ====')
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION:
                console.log('UPDATE_PROGRESSION ====')
                this.progressBar.progress = event.getPercent();

                // var msg = event.getMessage();
                // if (msg) {
                // }
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
                console.log('ERROR_DOWNLOAD_MANIFEST ====')
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                console.log('ERROR_PARSE_MANIFEST ====')
                G.scene.toast('更新失败，请重启游戏');
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                console.log('ALREADY_UP_TO_DATE ====')
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED:
                console.log('UPDATE_FINISHED ====')
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED:
                console.log('UPDATE_FAILED ====')
                this._updating = false;
                this._retry();
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING:
                console.log('ERROR_UPDATING ====')
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS:
                console.log('ERROR_DECOMPRESS ====')
                break;
            default:
                break;
        }

        if (failed) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            this._updating = false;

            this.enterArgs.delegate && this.enterArgs.delegate();
        }

        if (needRestart) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            // Prepend the manifest's search path
            var searchPaths = jsb.fileUtils.getSearchPaths();
            var newPaths = this._am.getLocalManifest().getSearchPaths();
            Array.prototype.unshift.apply(searchPaths, newPaths);
            // This value will be retrieved and appended to the default search path during game startup,
            // please refer to samples/js-tests/main.js for detailed usage.
            // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
            cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);

            cc.audioEngine.stopAll();
            console.log('更新成功，请重启游戏')
            cc.game.restart();
        }
    },

    _retry: function () {
        if (this.canRetryTime <= 0) {
            this.enterArgs.delegate && this.enterArgs.delegate();
            return;
        }
        this.canRetryTime--;

        if (!this._updating) {
            this._am.downloadFailedAssets();
        }
    },

    _checkUpdate: function () {
        if (this._updating) {
            return;
        }

        if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
            this.enterArgs.delegate && this.enterArgs.delegate();
            return;
        }
        this._am.setEventCallback(this._checkCb.bind(this));

        this._am.checkUpdate();
        this._updating = true;
        console.log('检测更新')
    },

    _hotUpdate: function () {
        if (this._am && !this._updating) {
            console.log('开始更新')
            this._am.setEventCallback(this._updateCb.bind(this));

            this._failCount = 0;
            this._am.update();
            this._updating = true;
        }
    },

    // use this for initialization
    _initAssetsManager: function () {
        let remoteAssetsDirPath = this.getRemoteAssetsDirPath();
        // Setup your own version compare handler, versionA and B is versions in string
        // if the return value greater than 0, versionA is greater than B,
        // if the return value equals 0, versionA equals to B,
        // if the return value smaller than 0, versionA is smaller than B.
        this.versionCompareHandle = function (versionA, versionB) {
            cc.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                else {
                    return a - b;
                }
            }
            if (vB.length > vA.length) {
                return -1;
            }
            else {
                return 0;
            }
        };

        // Init with empty manifest url for testing custom manifest
        this._am = new jsb.AssetsManager('', remoteAssetsDirPath, this.versionCompareHandle);

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            var url = this.manifestUrl.nativeUrl;
            let lManifestStr = jsb.fileUtils.getStringFromFile(url);
            try {
                let lManifestJObj = JSON.parse(lManifestStr);
                lManifestJObj.packageUrl = G.config.remoteUrl;
                lManifestJObj.remoteManifestUrl = cc.path.join(lManifestJObj.packageUrl, 'project.manifest');
                lManifestJObj.remoteVersionUrl = cc.path.join(lManifestJObj.packageUrl, 'version.manifest');
                let lCustomManifestStr = JSON.stringify(lManifestJObj);
                console.log(lCustomManifestStr)
                let lManifest = new jsb.Manifest(lCustomManifestStr, remoteAssetsDirPath);
                this._am.loadLocalManifest(lManifest, remoteAssetsDirPath);
            } catch (ex) {
                console.log('解析热更新配置失败');
            }
            // Resolve md5 url
        }

        // Setup the verification callback, but we don't have md5 check function yet, so only print some message
        // Return true if the verification passed, otherwise return false
        this._am.setVerifyCallback(function (path, asset) {
            // When asset is compressed, we don't need to check its md5, because zip file have been deleted.
            let compressed = asset.compressed;
            // Retrieve the correct md5 value.
            let expectedMD5 = asset.md5;
            // asset.path is relative path and path is absolute.
            let relativePath = asset.path;
            // The size of asset file, but this value could be absent.
            let bytes = asset.size;

            // 跳过manifest检测
            if (path.substring(path.length - 9) === '.manifest') {
                return true;
            }

            let fileBytes = jsb.fileUtils.getFileSize(path);
            let diffBytes = bytes - fileBytes;
            if (diffBytes >= 0.1 || diffBytes <= -0.1) {
                return false;
            }

            if (compressed) {
                return true;
            } else {
                return true;
            }
        });

        if (cc.sys.os === cc.sys.OS_ANDROID) {
            // Some Android device may slow down the download process when concurrent tasks is too much.
            // The value may not be accurate, please do more test and find what's most suitable for your game.
            this._am.setMaxConcurrentTask(2);
        }

        this.progressBar.progress = 0;
        console.log('am准备完成')
    },

    getRemoteAssetsDirPath: function () {
        let remoteAssetsDirPath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'RemoteAssets');
        return remoteAssetsDirPath;
    },

    onDestroy: function () {
        if (this._updateListener) {
            this._am.setEventCallback(null);
            this._updateListener = null;
        }
    }
});